﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;

namespace HYCodeBase.ExcelUtility.ExcelORM
{
	public class ExcelORMManger
	{
		public ExcelORMManger(Dictionary<string, ChageValueDelegate> inputAppendTransformer = null)
		{
			if (inputAppendTransformer == null)
			{
				this.m_useChangeDelDic = new Dictionary<string, ChageValueDelegate>();
				return;
			}
			this.m_useChangeDelDic = inputAppendTransformer;
		}

		public bool TryRead<T>(string inputPath, out List<T> lstReadedValue) where T : class
		{
			lstReadedValue = new List<T>();
			TypeInfo typeInfo = this.RegisteredType<T>(false);
			if (typeInfo == null)
			{
				return false;
			}
			FileInfo fileInfo = new FileInfo(inputPath);
			if (!fileInfo.Exists)
			{
				return false;
			}
			IWorkbook workbook = null;
			if (fileInfo.Extension.ToLower().Equals(".xlsx"))
			{
				workbook = new XSSFWorkbook(fileInfo.FullName);
			}
			else if (fileInfo.Extension.ToLower().Equals(".xls"))
			{
				using (FileStream fileStream = new FileStream(fileInfo.FullName, FileMode.Open))
				{
					workbook = new HSSFWorkbook(fileStream);
				}
			}
			List<object> source = typeInfo.ReadWorkBook(workbook);
			lstReadedValue = source.Cast<T>().ToList<T>();
			workbook.Close();
			return lstReadedValue.Count != 0;
		}

		public bool TryWrite<T>(string inputPath, List<T> inputObjects, bool overWriteIfExists = true)
		{
			FileInfo fileInfo = new FileInfo(inputPath);
			if (fileInfo.Exists)
			{
				if (overWriteIfExists)
				{
					try
					{
						fileInfo.Delete();
						goto IL_21;
					}
					catch (Exception)
					{
						return false;
					}
				}
				return false;
			}
			IL_21:
			bool ifIsXlsx;
			if (fileInfo.Extension.ToLower().Equals(".xlsx"))
			{
				ifIsXlsx = true;
			}
			else
			{
				if (!fileInfo.Extension.ToLower().Equals(".xls"))
				{
					return false;
				}
				ifIsXlsx = false;
			}
			IWorkbook workbook = null;
			if (!this.TryWrite<T>(inputObjects, ifIsXlsx, out workbook))
			{
				return false;
			}
			bool result;
			try
			{
				using (Stream stream = new FileStream(inputPath, FileMode.CreateNew, FileAccess.Write))
				{
					workbook.Write(stream);
				}
				result = true;
			}
			catch (Exception)
			{
				result = false;
			}
			finally
			{
				workbook.Close();
			}
			return result;
		}

		public bool TryWrite<T>(List<T> inputObjects, bool ifIsXlsx, out IWorkbook useWorkBook)
		{
			useWorkBook = null;
			if (inputObjects == null || inputObjects.Count == 0)
			{
				return false;
			}
			TypeInfo typeInfo = this.RegisteredType<T>(true);
			if (typeInfo == null)
			{
				return false;
			}
			if (ifIsXlsx)
			{
				useWorkBook = new XSSFWorkbook();
			}
			else
			{
				useWorkBook = new HSSFWorkbook();
			}
			typeInfo.WriteToWorkBook(useWorkBook, inputObjects.Cast<object>().ToList<object>());
			return true;
		}

		private TypeInfo RegisteredType<T>(bool ifIsWrite = false)
		{
			Type typeFromHandle = typeof(T);
			this.RegisteredType(typeFromHandle, ifIsWrite);
			ExcelORMManger.m_useReaderWriterLocker.EnterReadLock();
			TypeInfo result = ExcelORMManger.m_useTypeMap[typeFromHandle];
			ExcelORMManger.m_useReaderWriterLocker.ExitReadLock();
			return result;
		}

		private void RegisteredType(Type inputType, bool ifIsWrite = false)
		{
			if (ExcelORMManger.CheckInput(inputType))
			{
				return;
			}
			object[] customAttributes = inputType.GetCustomAttributes(ExcelORMManger.m_useClassAttributeType, false);
			if (customAttributes == null || 1 != customAttributes.Length)
			{
				ExcelORMManger.WriteToDic(inputType, null);
				return;
			}
			ClassAttribute classAttribute = (ClassAttribute)customAttributes[0];
			if (0 > classAttribute.SheetIndex && string.IsNullOrWhiteSpace(classAttribute.SheetName) && !ifIsWrite)
			{
				ExcelORMManger.WriteToDic(inputType, null);
				return;
			}
			Dictionary<PropertyInfo, PropertyAttribute> dictionary = new Dictionary<PropertyInfo, PropertyAttribute>();
			foreach (PropertyInfo propertyInfo in inputType.GetProperties())
			{
				if (propertyInfo.CanRead && propertyInfo.CanWrite)
				{
					PropertyAttribute propertyAttribute = propertyInfo.GetCustomAttribute(ExcelORMManger.m_usePropertyAttributeType) as PropertyAttribute;
					if (((propertyAttribute != null && (0 <= propertyAttribute.UseColumnIndex || !string.IsNullOrWhiteSpace(propertyAttribute.UseColumnName))) || ifIsWrite) && (TypePropertyInfo.CheckProperty(propertyInfo) || this.CheckTransformer(propertyAttribute)))
					{
						if (this.CheckTransformer(propertyAttribute))
						{
							propertyAttribute.UseTransformer = this.m_useChangeDelDic[propertyAttribute.UseTransformerName];
						}
						dictionary.Add(propertyInfo, propertyAttribute);
					}
				}
			}
			if (dictionary.Count != 0)
			{
				ExcelORMManger.WriteToDic(inputType, new TypeInfo(inputType, classAttribute, dictionary));
				return;
			}
			ExcelORMManger.WriteToDic(inputType, null);
		}

		private static void WriteToDic(Type inputType, TypeInfo inputTypeInfo)
		{
			ExcelORMManger.m_useReaderWriterLocker.EnterWriteLock();
			if (!ExcelORMManger.m_useTypeMap.ContainsKey(inputType))
			{
				ExcelORMManger.m_useTypeMap.Add(inputType, inputTypeInfo);
			}
			ExcelORMManger.m_useReaderWriterLocker.ExitWriteLock();
		}

		private static bool CheckInput(Type inputType)
		{
			ExcelORMManger.m_useReaderWriterLocker.EnterReadLock();
			bool result = null == inputType || ExcelORMManger.m_useTypeMap.ContainsKey(inputType);
			ExcelORMManger.m_useReaderWriterLocker.ExitReadLock();
			return result;
		}

		private bool CheckTransformer(PropertyAttribute tempPropertyAttribute)
		{
			return !string.IsNullOrWhiteSpace(tempPropertyAttribute.UseTransformerName) && this.m_useChangeDelDic.ContainsKey(tempPropertyAttribute.UseTransformerName) && this.m_useChangeDelDic[tempPropertyAttribute.UseTransformerName] != null;
		}

		private static Type m_useClassAttributeType = typeof(ClassAttribute);

		private static Type m_usePropertyAttributeType = typeof(PropertyAttribute);

		private static ReaderWriterLockSlim m_useReaderWriterLocker = new ReaderWriterLockSlim();

		private static Dictionary<Type, TypeInfo> m_useTypeMap = new Dictionary<Type, TypeInfo>();

		private Dictionary<string, ChageValueDelegate> m_useChangeDelDic = new Dictionary<string, ChageValueDelegate>();

		private const string m_strxlsx = ".xlsx";

		private const string m_strxls = ".xls";
	}
}
